/* Network function definitions, communication between client and server */

#ifndef NETWORK_H_
#define NETWORK_H_

#include <sys/socket.h>
#include "player.h"
#include "items.h"
#include "main.h"

#define MAX_CLIENTS MAX_PLAYERS
#define MAX_CHATLEN 250
#define BUFSIZE 1024

#define SERVER_PORT 6112
// #define SERVER_PORT 28888
#define CTXSTR(x) CTSTR(x)
#define CTSTR(x) #x

/* Contains information about your peers in the game. All of them are nicely
  visible in the lobby screen and the server periodically sends out their info. */
typedef struct
{
	int ready; // ready or not
	char nickname [MAX_NAMELEN];
	
	// the following fields are only used on server
	int uid; // ID # chosen by client to mark their messages with
	struct sockaddr_storage address;
	int disc_countdown;
} Client;

/* types of client to server messages */
typedef enum  
{ 
	CtoS_NOMSG = 0, /* On receive: no message pending */
	CtoS_ILLEGALMSG, /* unidentified incoming message or other error condition */
	CtoS_PULSE, /* Message sent at regular intervals to keepalive connection */
	CtoS_HELLO,  /* (int uid, char nickname [MAX_NAMELEN]) client's first message to server. */
	CtoS_REPEAT, /* (int seq) client asks the server to resend all past packets starting from the one numbered [seq] */
	CtoS_CHAT,  /* (char line [MAX_CHATLEN]) contains chat message to be sent to everyone */
	CtoS_LOBBY_ADDPLAYER, /* (Playerdata data) client adds a player to the lobby. 1 client can control multiple players */
	CtoS_LOBBY_SETPLAYERDATA, /* (int slot, Playerdata data) client changes some data for registered player. Like name, character etc. */
	CtoS_LOBBY_REMOVEPLAYER, /* (int slot) client removes player with given index */
	CtoS_LOBBY_READY, /* client signals ready for game start */
	CtoS_LOBBY_NOTREADY, /* client undoes ready */
	CtoS_INGAME_ACTION, /* (const Action* action) set a desired action at a desired time */
	CtoS_INGAME_SETINVENTORY, /* (int player, Inventory inv) modifies a player inventory */
} CtoSmsgType;

typedef enum  
{ 
	StoC_NOMSG = 0, /* On receive: no message pending */
	StoC_ILLEGALMSG,  /* unidentified incoming message or other error condition */
	StoC_PULSE, /* Message sent at regular intervals to keepalive connection */
	StoC_KICK, /* Tell a client to f* off, no sequence info */
	StoC_NOTIFY, /* (char line [MAX_CHATLEN]) A message from the server to be displayed at the client */
	StoC_CHAT, /* (char line [MAX_CHATLEN]) contains a full chat message, display please */
	StoC_ALLINFO, /* (struct allinfo) Transmitted to freshly connected clients. If game is in progress, they have to wait. */
	StoC_LOBBY_NEWCLIENT, /* (int clientidx, char nickname [MAX_NAMELEN]) a new client has arrived. */
	StoC_LOBBY_NEWPLAYER, /* (int owner, int playeridx, Playerdata data) a new player has been added */
	StoC_LOBBY_PLAYERLEAVE, /* (int playeridx) */
	StoC_LOBBY_CLIENTLEAVE, /* (int clientidx) */
	StoC_LOBBY_SEEDGAME, /* (unsigned long seed) The server shares with the clients the seed used to random-generate all game content in this round. */
	StoC_LOBBY_CLIENTREADY, /* (int clientidx) Signals that a client is setting READY */
	StoC_LOBBY_CLIENTNOTREADY, /* (int clientidx) Signals that a client is setting NOTREADY */
	StoC_LOBBY_STARTGAME, /* Switch from lobby to ingame */
	StoC_INGAME_ACTION, /* Some actor wants to enqueue an action. */
	StoC_INGAME_DAMAGE, /* Damage is dealt by an attacker to a victim */
	StoC_INGAME_DIE, /* Actor is out of HP and dies */
	StoC_INGAME_SETPLAYER, /* (int playeridx, Player player) gives complete update on a player */
	StoC_INGAME_OVER, /* (int winner) The game is finished, back to the lobby */
} StoCmsgType;
	
typedef struct 
{
	CtoSmsgType type;
	int uid;
	
	union {
		char nickname [MAX_NAMELEN]; // HELLO
		char line [MAX_CHATLEN]; // CHAT
		int seq; // REPEAT
		struct {
			int player;
			Inventory inv;
		}; // INGAME_SETINVENTORY
		struct {
			int slot;
			Playerdata data;
		};  // LOBBY_ADDPLAYER, LOBBY_SETPLAYERDATA, LOBBY_REMOVEPLAYER
		Action action; // INGAME_ACTION
	};
} CtoSmessage;

typedef struct 
{
	StoCmsgType type;
	
	union {
		char line [MAX_CHATLEN]; // NOTIFY, CHAT
		struct {
			int clientidx;
			char nickname [MAX_NAMELEN]; 
		}; // LOBBY_NEWCLIENT, LOBBY_CLIENTLEAVE
		struct {
			int owner;
			int playeridx;
			Player player; /* only player.data is used in LOBBY_NEWPLAYER */
		};  // LOBBY_NEWPLAYER, LOBBY_PLAYERLEAVE, INGAME_SETPLAYER
		unsigned long seed; // LOBBY_SEEDGAME
		Action action; // INGAME_ACTION
		struct {
			int time;
			coord_t where;
			int attacker; // Actor ID
			int victim; // Actor ID
			int weapon;
			int damage;
			int hp; // updated hp value of the victim
		} damage; // INGAME_DAMAGE, INGAME_DIE
		struct {
			int who;
			int level;
			int hp;
			Inventory inv;
		}; // INGAME_SETPLAYER
		struct {
			int state; // global game state
			Client peer [MAX_CLIENTS];
			Player player [MAX_CLIENTS]; // player[x] does not necessarily belong to peer[x]
			int owner [MAX_CLIENTS]; // but player[x] belongs to client[owner[x]]
		} allinfo; // ALLINFO
		int winner; // INGAME_OVER
	};
} StoCmessage;

/* All the clients which are currently connected and their players */
extern Client peer [MAX_CLIENTS];
extern Player player [MAX_CLIENTS]; // player[x] does not necessarily belong to peer[x]
extern int owner [MAX_CLIENTS]; // but player[x] belongs to client[owner[x]]
extern int my_uid; // Only on client

extern int client_by_uid (int uid); // Only on server

/* Funny callbacks! (unused at this time) */
extern void (*notify_clientjoin) (int index);
extern void (*notify_playerjoin) (int index);
extern void (*notify_clientleave) (int index);
extern void (*notify_playerleave) (int index);

/* initializes the socket and server address info after the user has entered a server host name */
void network_init (const char* servername);
void network_update ();
void network_cleanup ();

/* Send or get message */
void send_CtoSmessage (CtoSmessage* msg);
void send_StoCmessage (StoCmessage* msg, int recipient);
void receive_CtoSmessage (CtoSmessage* msg, int* sender);
void receive_StoCmessage (StoCmessage* msg);

#endif /* NETWORK_H_ */
